package com.gx.service.impl;


import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.gx.common.config.flowable.FlowServiceFactory;
import com.gx.common.enums.FlowCommentEnum;
import com.gx.common.enums.FlowMsgEnum;
import com.gx.common.exception.CommonException;
import com.gx.common.exception.FlowException;
import com.gx.mapper.FlowableTaskMapper;
import com.gx.model.dto.definition.FlowCommentDto;
import com.gx.model.dto.task.FlowTaskCompleteDto;
import com.gx.model.dto.task.FlowTaskReturnDto;
import com.gx.model.dto.task.TaskQueryDto;
import com.gx.model.pojo.TbBusinessTask;
import com.gx.model.pojo.TbFlowEnd;
import com.gx.model.vo.FlowTaskVo;
import com.gx.model.vo.MyHisTaskVo;
import com.gx.model.vo.ReturnTaskVo;
import com.gx.service.FlowInfoService;
import com.gx.service.FlowTaskService;
import com.gx.service.TbBusinessTaskService;
import com.gx.service.TbFlowMsgService;
import com.gx.utils.FlowableUtils;
import com.gx.utils.MessageUtils;
import lombok.extern.slf4j.Slf4j;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.bpmn.model.FlowElement;
import org.flowable.bpmn.model.Process;
import org.flowable.bpmn.model.UserTask;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.history.HistoricProcessInstanceQuery;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.repository.ProcessDefinitionQuery;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.identitylink.api.IdentityLink;
import org.flowable.task.api.DelegationState;
import org.flowable.task.api.Task;
import org.flowable.task.api.TaskInfo;
import org.flowable.task.api.TaskQuery;
import org.flowable.task.api.history.HistoricTaskInstance;
import org.flowable.task.api.history.HistoricTaskInstanceQuery;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;

/**
 * @Author Liu-pj
 * @Date 2022/3/15 16:50
 * @Desc 流程任务操作
 **/
@Service
@Slf4j
public class FlowTaskServiceImpl extends FlowServiceFactory implements FlowTaskService {
    @Autowired
    private TbBusinessTaskService businessTaskService;

    @Autowired
    private FlowInfoService flowInfoService;

    @Autowired
    private TbFlowMsgService flowMsgService;

    @Autowired
    private FlowableTaskMapper flowableTaskMapper;

    /**
     * 我的任务列表
     *
     * @param dto 参数
     * @return 任务列表
     */
    @Override
    public Page<FlowTaskVo> myProcess(TaskQueryDto dto) {
        dto.checkPageParam();
        Integer currPage = dto.getCurrPage();
        Integer pageSize = dto.getPageSize();
        Page<FlowTaskVo> page = new Page<>();
        // 条件封装
        HistoricProcessInstanceQuery historicProcessInstanceQuery = this.getMyTaskQuery(dto);
        // 分页查询流程信息
        List<HistoricProcessInstance> historicProcessInstances = historicProcessInstanceQuery
                .listPage((currPage - 1) * pageSize, pageSize);
        List<FlowTaskVo> flowResList = historicProcessInstances.stream()
                .map(this::mapToFlowTaskVo)
                .collect(Collectors.toList());
        page.setTotal(historicProcessInstanceQuery.count());
        page.setRecords(flowResList);
        page.setCurrent(currPage);
        page.setSize(pageSize);
        return page;
    }


    /**
     * 已处理任务列表
     *
     * @param dto 参数
     * @return 任务列表
     */
    @Override
    public Page<FlowTaskVo> finishedList(TaskQueryDto dto) {
        HistoricTaskInstanceQuery historicTaskInstanceQuery = this.historyService.createHistoricTaskInstanceQuery();
        return null;
    }

    /**
     * 已处理任务列表
     *
     * @param dto 参数
     * @return 任务列表
     */
    @Override
    public Page<MyHisTaskVo> getMyHisTaskList(TaskQueryDto dto) {
        Page<MyHisTaskVo> page = new Page<>(dto.getCurrPage(), dto.getPageSize());
        this.flowableTaskMapper.getMyHisTaskList(page, dto.getDefName(), dto.getUserId());
        return page;
    }

    @Override
    public Page<FlowTaskVo> todoList(TaskQueryDto dto) {
        Integer currPage = dto.getCurrPage();
        Integer pageSize = dto.getPageSize();
        // 条件封装
        TaskQuery taskQuery = getTodoTaskQuery(dto);
        // 结果查询
        List<Task> taskList = taskQuery.listPage((currPage - 1) * pageSize, pageSize);
        // 使用Stream API进行映射，将Task列表转换为FlowTaskVo列表
        List<FlowTaskVo> resTaskList = taskList.stream()
                .map(this::mapToFlowTaskVo)
                .collect(Collectors.toList());
        // 创建Page对象并设置相关属性
        Page<FlowTaskVo> taskVoPage = new Page<>();
        taskVoPage.setRecords(resTaskList);
        taskVoPage.setTotal(taskQuery.count());
        taskVoPage.setCurrent(currPage);
        taskVoPage.setSize(pageSize);

        return taskVoPage;
    }

    /**
     * 任务审批
     *
     * @param completeDto 审批参数
     */
    @Override
    public void complete(FlowTaskCompleteDto completeDto) {
        String taskId = completeDto.getTaskId();
        Task task = getTaskById(taskId);
        //审批及签收
        taskService.setAssignee(taskId, completeDto.getUserId());
        //变量存储
        Map<String, Object> taskVariables = completeDto.getProcessVariables();
        if (CollUtil.isNotEmpty(taskVariables)) {
            taskService.setVariables(taskId, taskVariables);
        }
        //意见存储
        String taskCommon = JSONObject.toJSONString(completeDto.getComment());
        //委派任务
        if (DelegationState.PENDING.equals(task.getDelegationState())) {
            taskService.addComment(taskId, task.getProcessInstanceId(), FlowCommentEnum.DELEGATE.getType(), taskCommon);
            taskService.resolveTask(taskId);
        } else {
            taskService.addComment(taskId, task.getProcessInstanceId(), FlowCommentEnum.NORMAL.getType(), taskCommon);
            taskService.complete(taskId);
        }
        //维护流程信息
        saveTaskData(task.getProcessInstanceId());
    }


    /**
     * 任务回退
     *
     * @param returnDto 回退参数
     */
    @Override
    public void taskReturn(FlowTaskReturnDto returnDto) {
        String taskId = returnDto.getTaskId();
        FlowCommentDto comment = returnDto.getComment();
        String targetKey = returnDto.getTargetKey();
        String userId = returnDto.getUserId();
        Map<String, Object> processVariables = returnDto.getProcessVariables();
        Task task = getTaskById(taskId);
        if (CollUtil.isNotEmpty(processVariables)) {
            taskService.setVariables(taskId, processVariables);
        }
        ProcessDefinition processDefinition = getProcessDefinitionById(task.getProcessDefinitionId());
        //实例信息获取
        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
                .processInstanceId(task.getProcessInstanceId())
                .singleResult();
        // 获取所有节点信息
        Process process = repositoryService.getBpmnModel(processDefinition.getId())
                .getProcesses()
                .get(0);
        // 获取全部节点列表，包含子节点
        Collection<FlowElement> allElements = FlowableUtils.getAllElements(process.getFlowElements(), null);
        TbBusinessTask businessTask = businessTaskService.getOne(new LambdaQueryWrapper<TbBusinessTask>()
                .eq(TbBusinessTask::getInstanceId, task.getProcessInstanceId()));
        // 获取当前任务节点元素
        FlowElement source = null;
        // 获取跳转的节点元素
        FlowElement target = null;
        if (allElements != null) {
            for (FlowElement flowElement : allElements) {
                // 当前任务节点元素
                if (StrUtil.equals(flowElement.getId(), task.getTaskDefinitionKey())) {
                    source = flowElement;
                }
                // 跳转的节点元素
                if (StrUtil.equals(flowElement.getId(), targetKey)) {
                    target = flowElement;
                }
            }
        }
        // 从当前节点向前扫描
        // 如果存在路线上不存在目标节点，说明目标节点是在网关上或非同一路线上，不可跳转
        // 否则目标节点相对于当前节点，属于串行
        Boolean isSequential = FlowableUtils.iteratorCheckSequentialReferTarget(source, targetKey, null, null);
        if (!isSequential) {
            throw new CommonException("当前节点相对于目标节点，不属于串行关系，无法回退");
        }
        UserTask userTask = (UserTask) target;
        if (userTask == null) {
            throw new CommonException("未识别到目标节点信息");
        }
        if (StrUtil.isNotBlank(userTask.getSkipExpression())) {
            throw new CommonException("不可退回到自动跳过节点!");
        }
        List<String> candidateUsers = userTask.getCandidateUsers();
        String assignee = userTask.getAssignee();
        List<String> candidateGroups = userTask.getCandidateGroups();
        //是否退回到申请
        AtomicBoolean flag = new AtomicBoolean(false);
        if (CollUtil.isEmpty(candidateUsers) && StrUtil.isBlank(assignee) && CollUtil.isEmpty(candidateGroups)) {
            flag.set(true);
        }
        // 获取所有正常进行的任务节点 Key，这些任务不能直接使用，需要找出其中需要撤回的任务
        List<Task> runTaskList = taskService.createTaskQuery()
                .processInstanceId(task.getProcessInstanceId())
                .list();
        List<String> runTaskKeyList = new ArrayList<>();
        runTaskList.forEach(item -> runTaskKeyList.add(item.getTaskDefinitionKey()));
        // 需退回任务列表
        List<String> currentIds = new ArrayList<>();
        // 通过父级网关的出口连线，结合 runTaskList 比对，获取需要撤回的任务
        List<UserTask> currentUserTaskList = FlowableUtils.iteratorFindChildUserTasks(target, runTaskKeyList, null, null);
        currentUserTaskList.forEach(item -> currentIds.add(item.getId()));
        // 循环获取那些需要被撤回的节点的ID，用来设置驳回原因
        List<String> currentTaskIds = new ArrayList<>();
        currentIds.forEach(currentId -> {
            runTaskList.stream()
                    .filter(runTask -> currentId.equals(runTask.getTaskDefinitionKey()))
                    .map(TaskInfo::getId)
                    .forEach(currentTaskIds::add);
        });
        String common = JSONObject.toJSONString(comment);
        // 设置回退意见
        for (String currentTaskId : currentTaskIds) {
            taskService.addComment(currentTaskId, task.getProcessInstanceId(), FlowCommentEnum.ROLL_BACK.getType(), common);
        }
        //设置节点操作人
        taskService.setAssignee(taskId, userId);
        //节点移动
        runtimeService.createChangeActivityStateBuilder()
                .processInstanceId(task.getProcessInstanceId())
                .moveActivityIdsToSingleActivityId(currentIds, targetKey)
                .changeState();
        //获取移动后待审批
        List<Task> nextTaskList = taskService.createTaskQuery()
                .processInstanceId(task.getProcessInstanceId())
                .list();
        ArrayList<String> nextTaskIds = new ArrayList<>();
        ArrayList<String> nextTaskNames = new ArrayList<>();
        for (Task nextTask : nextTaskList) {
            nextTaskIds.add(nextTask.getId());
            nextTaskNames.add(nextTask.getName());
            if (!flag.get()) {
                sendNextTaskMsg(processDefinition.getName(), nextTask);
            }
        }
        if (flag.get()) {
            String msg = MessageUtils.updateMessage(processDefinition.getName(), getProcessVariables(taskId));
            this.flowMsgService.sendUserMsg(ListUtil.of(processInstance.getStartUserId()), msg, FlowMsgEnum.WAIT_UPDATE.getType());
        }
        //修改流程节点状态
        if (CollUtil.isNotEmpty(nextTaskIds)) {
            flowInfoService.updateFlowStart(businessTask.getId(),
                    StrUtil.join(",", nextTaskIds),
                    StrUtil.join(",", nextTaskNames),
                    getProcessVariables(nextTaskIds.get(0))
            );
        }
    }

    /**
     * 任务可回退列表
     *
     * @param taskId 任务Id
     * @return 列表
     */
    @Override
    public List<ReturnTaskVo> findReturnTaskList(String taskId) {
        // 获取当前任务
        Task task = getTaskById(taskId);
        // 获取当前任务节点
        UserTask userTask = getCurrentUserTask(task);
        List<HistoricTaskInstance> taskInstanceList = getHistoricTaskInstancesByInsId(task.getProcessInstanceId());
        // 收集带有跳过表达式的任务定义键
        Set<String> skipDefKeys = collectSkipDefKeys();
        // 收集可回退的任务节点
        List<ReturnTaskVo> voList = new ArrayList<>();
        for (HistoricTaskInstance instance : taskInstanceList) {
            String name = instance.getName();
            String taskDefinitionKey = instance.getTaskDefinitionKey();
            if (!skipDefKeys.contains(taskDefinitionKey) && instance.getEndTime() != null) {
                ReturnTaskVo returnTaskVo = new ReturnTaskVo();
                returnTaskVo.setId(taskDefinitionKey);
                returnTaskVo.setName(name);
                voList.add(returnTaskVo);
            }
        }
        // 获取所有可行的路线上的节点
        List<List<UserTask>> roads = FlowableUtils.findRoad(userTask, null, null, null);
        Set<String> roadUserTaskKeys = roads.stream()
                .flatMap(List::stream)
                .map(UserTask::getId)
                .collect(Collectors.toSet());

        List<ReturnTaskVo> res = voList.stream()
                .filter(returnTaskVo -> roadUserTaskKeys.contains(returnTaskVo.getId()))
                .collect(Collectors.toList());

        Collections.reverse(res);
        return res;
    }

    /**
     * 下一节点通知
     *
     * @param processDefinitionName 流程名称
     * @param nextTask              待办列表
     */
    @Override
    public void sendNextTaskMsg(String processDefinitionName, Task nextTask) {
        //发送下个节点通知信息
        HashSet<String> userIds = new HashSet<>();
        HashSet<String> groupIds = new HashSet<>();
        //获取节点待办人
        List<IdentityLink> identityLinks = taskService.getIdentityLinksForTask(nextTask.getId());
        for (IdentityLink identityLink : identityLinks) {
            if (ObjectUtil.isNotNull(identityLink)) {
                if (StrUtil.isNotBlank(identityLink.getUserId())) {
                    String[] split = identityLink.getUserId().split(",");
                    userIds.addAll(Arrays.asList(split));
                } else {
                    String[] split = identityLink.getGroupId().split(",");
                    groupIds.addAll(Arrays.asList(split));
                }
            }
            String message = MessageUtils.waitMessage(nextTask.getId(), processDefinitionName, getProcessVariables(nextTask.getId()));
            this.flowMsgService.sendGroupUserMsg(userIds, groupIds, message, FlowMsgEnum.WAIT_COMPLETE.getType());
        }
    }

    /**
     * 获取定义详情
     *
     * @param definitionId 定义id
     * @return 结果
     */
    private ProcessDefinition getProcessDefinitionById(String definitionId) {
        // 获取流程定义信息
        return repositoryService.createProcessDefinitionQuery()
                .processDefinitionId(definitionId)
                .singleResult();
    }

    /**
     * 辅助方法：根据提供的任务获取当前 UserTask 节点。
     *
     * @param task 任务对象
     * @return 与任务对应的 UserTask
     */
    private UserTask getCurrentUserTask(Task task) {
        ProcessDefinition processDefinition = getProcessDefinitionById(task.getProcessDefinitionId());
        Process process = repositoryService.getBpmnModel(processDefinition.getId())
                .getProcesses().get(0);

        for (FlowElement flowElement : process.getFlowElements()) {
            if (flowElement instanceof UserTask && task.getTaskDefinitionKey().equals(flowElement.getId())) {
                return (UserTask) flowElement;
            }
        }
        throw new CommonException("未找到当前任务节点");
    }

    /**
     * 获取任务详情
     *
     * @param taskId 任务id
     * @return 结果
     */
    private Task getTaskById(String taskId) {
        Task task = taskService.createTaskQuery()
                .taskId(taskId)
                .singleResult();
        if (task == null) {
            throw new FlowException("任务不存在!");
        }
        return task;
    }

    /**
     * 获取历史任务列表
     *
     * @param insId 实例id
     * @return 结果
     */
    private List<HistoricTaskInstance> getHistoricTaskInstancesByInsId(String insId) {
        // 获取流程实例的历史任务列表
        return historyService.createHistoricTaskInstanceQuery()
                .processInstanceId(insId)
                .list();
    }

    /**
     * 辅助方法：收集具有跳过表达式的任务定义键。
     *
     * @return 带有跳过表达式的任务定义键集合
     */
    private Set<String> collectSkipDefKeys() {
        ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery();
        List<ProcessDefinition> processDefinitions = processDefinitionQuery.list();

        Set<String> skipDefKeys = new HashSet<>();
        for (ProcessDefinition processDefinition : processDefinitions) {
            BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinition.getId());
            Process process = bpmnModel.getProcesses().get(0);
            for (FlowElement flowElement : process.getFlowElements()) {
                if (flowElement instanceof UserTask) {
                    UserTask userTask = (UserTask) flowElement;
                    if (StrUtil.isNotBlank(userTask.getSkipExpression())) {
                        skipDefKeys.add(userTask.getId());
                    }
                }
            }
        }
        return skipDefKeys;
    }

    /**
     * 审批流程信息维护
     *
     * @param instanceId 实例id
     */
    private void saveTaskData(String instanceId) {
        //获取流程触发的信息
        TbBusinessTask businessTask = businessTaskService.getFlowByInstancesId(instanceId);
        HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery()
                .processInstanceId(instanceId)
                .singleResult();
        if (historicProcessInstance.getEndTime() != null) {
            //设置完结状态
            TbFlowEnd flowEnd = new TbFlowEnd();
            flowEnd.setTaskFormId(businessTask.getId());
            flowEnd.setStartUserId(historicProcessInstance.getStartUserId());
            flowEnd.setStartTime(historicProcessInstance.getStartTime());
            flowEnd.setOther(JSONObject.toJSONString(historicProcessInstance.getProcessVariables()));
            flowInfoService.saveFlowEnd(flowEnd);
            flowInfoService.delStartFlow(businessTask.getId());
            String message = MessageUtils.endMessage("", historicProcessInstance);
            flowMsgService.sendUserMsg(ListUtil.of(historicProcessInstance.getStartUserId()), message, FlowMsgEnum.END.getType());
        } else {
            List<Task> taskList = taskService.createTaskQuery()
                    .processInstanceId(historicProcessInstance.getId())
                    .list();
            ArrayList<String> nextTaskIds = new ArrayList<>();
            ArrayList<String> nextTaskNames = new ArrayList<>();
            for (Task nextTask : taskList) {
                //更新节点信息
                nextTaskIds.add(nextTask.getId());
                nextTaskNames.add(nextTask.getName());
                sendNextTaskMsg(historicProcessInstance.getProcessDefinitionName(), nextTask);
            }
            //更新节点状态
            if (CollUtil.isNotEmpty(taskList)) {
                flowInfoService.updateFlowStart(businessTask.getId(),
                        StrUtil.join(",", nextTaskIds),
                        StrUtil.join(",", nextTaskNames),
                        getProcessVariables(nextTaskIds.get(0))
                );
            }
        }
    }

    /**
     * 我的发起条件封装
     *
     * @param dto 条件
     * @return 结果
     */
    private HistoricProcessInstanceQuery getMyTaskQuery(TaskQueryDto dto) {
        String userId = dto.getUserId();
        String defName = dto.getDefName();
        Map<String, String> variableCondition = dto.getVariableCondition();
        HistoricProcessInstanceQuery historicProcessInstanceQuery = historyService.createHistoricProcessInstanceQuery()
                .includeProcessVariables()
                .orderByProcessInstanceStartTime()
                .desc();
        if (StrUtil.isNotBlank(userId)) {
            historicProcessInstanceQuery.startedBy(userId);
        }
        if (StrUtil.isNotBlank(defName)) {
            historicProcessInstanceQuery.processDefinitionName(defName);
        }
        if (CollUtil.isNotEmpty(variableCondition)) {
            for (Map.Entry<String, String> condition : variableCondition.entrySet()) {
                historicProcessInstanceQuery.variableValueLike(condition.getKey(), "%" + condition.getValue() + "%");
            }
        }
        return historicProcessInstanceQuery;
    }

    /**
     * 待办任务条件封装
     */
    private TaskQuery getTodoTaskQuery(TaskQueryDto dto) {
        dto.checkPageParam();
        String userId = dto.getUserId();
        List<String> groupIds = dto.getGroupIds();
        String taskName = dto.getTaskName();
        String defName = dto.getDefName();
        Map<String, String> variableCondition = dto.getVariableCondition();
        TaskQuery taskQuery = taskService.createTaskQuery();
        taskQuery.active()
                .includeProcessVariables()
                .orderByTaskCreateTime()
                .desc();
        if (CollUtil.isNotEmpty(groupIds) || StrUtil.isNotBlank(userId)) {
            taskQuery.or();
        }
        if (StrUtil.isNotBlank(userId)) {
            taskQuery.taskAssignee(userId);
            taskQuery.taskCandidateUser(userId);
        }
        if (CollUtil.isNotEmpty(groupIds)) {
            taskQuery.taskCandidateGroupIn(groupIds);
        }
        if (CollUtil.isNotEmpty(groupIds) || StrUtil.isNotBlank(userId)) {
            taskQuery.endOr();
        }
        if (StrUtil.isNotBlank(taskName)) {
            taskQuery.taskNameLike("%" + dto.getTaskName() + "%");
        }
        if (StrUtil.isNotBlank(defName)) {
            taskQuery.processDefinitionNameLike("%" + defName + "%");
        }
        if (CollUtil.isNotEmpty(variableCondition)) {
            for (Map.Entry<String, String> condition : variableCondition.entrySet()) {
                taskQuery.processVariableValueLike(condition.getKey(), "%" + condition.getValue() + "%");
            }
        }
        return taskQuery;
    }

    /**
     * 我的待办列表封装
     *
     * @param task 任务
     * @return 结果
     */
    private FlowTaskVo mapToFlowTaskVo(Task task) {
        FlowTaskVo flowTaskVo = new FlowTaskVo();
        String processInstanceId = task.getProcessInstanceId();

        // 流程实例信息
        HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery()
                .processInstanceId(processInstanceId)
                .singleResult();
        flowTaskVo.setStartUserId(historicProcessInstance.getStartUserId());
        flowTaskVo.setProcVars(task.getProcessVariables());
        flowTaskVo.setTaskId(task.getId());
        flowTaskVo.setTaskName(task.getName());
        flowTaskVo.setStartTime(historicProcessInstance.getStartTime());
        flowTaskVo.setCreateTime(task.getCreateTime());
        flowTaskVo.setProcDefId(task.getProcessDefinitionId());
        flowTaskVo.setProcDefName(historicProcessInstance.getProcessDefinitionName());
        flowTaskVo.setInstanceId(processInstanceId);
        flowTaskVo.setDeployId(historicProcessInstance.getDeploymentId());
        flowTaskVo.setAssigneeId(task.getAssignee());
        flowTaskVo.setCategory(task.getCategory());
        flowTaskVo.setStartUserName(getStartUserName(task.getProcessVariables()));

        return flowTaskVo;
    }

    /**
     * 我的任务列表封装
     *
     * @param hisIns 实例信息
     * @return 结果
     */
    private FlowTaskVo mapToFlowTaskVo(HistoricProcessInstance hisIns) {
        FlowTaskVo flowTask = new FlowTaskVo();

        // 计算耗时
        long time = Objects.nonNull(hisIns.getEndTime())
                ? hisIns.getEndTime().getTime() - hisIns.getStartTime().getTime()
                : System.currentTimeMillis() - hisIns.getStartTime().getTime();
        flowTask.setDuration(getDate(time));

        // 任务基本信息
        Map<String, Object> processVariables = hisIns.getProcessVariables();
        flowTask.setCreateTime(hisIns.getStartTime());
        flowTask.setFinishTime(hisIns.getEndTime());
        flowTask.setInstanceId(hisIns.getId());
        flowTask.setStartUserId(hisIns.getStartUserId());
        flowTask.setStartUserName(getStartUserName(processVariables));
        flowTask.setProcVars(processVariables);

        // 流程定义信息
        ProcessDefinition pd = repositoryService.createProcessDefinitionQuery()
                .processDefinitionId(hisIns.getProcessDefinitionId())
                .singleResult();
        flowTask.setDeployId(pd.getDeploymentId());
        flowTask.setProcDefName(pd.getName());
        flowTask.setInstanceId(hisIns.getId());
        flowTask.setStartTime(hisIns.getStartTime());

        // 当前所处流程
        List<Task> taskList = taskService.createTaskQuery()
                .processInstanceId(hisIns.getId())
                .list();
        List<String> ids = new ArrayList<>();
        List<String> names = new ArrayList<>();
        if (ObjectUtil.isNotEmpty(taskList)) {
            taskList.forEach(task -> {
                ids.add(task.getId());
                names.add(task.getName());
            });
            flowTask.setNowTaskId(StrUtil.join(",", ids));
            JSONObject nowTask = new JSONObject();
            nowTask.put("taskId", StrUtil.join(",", ids));
            nowTask.put("taskName", StrUtil.join(",", names));
            flowTask.setNowTask(nowTask);
            flowTask.setTaskId(StrUtil.join(",", ids));
        } else {
            List<HistoricTaskInstance> historicTaskInstance = historyService
                    .createHistoricTaskInstanceQuery()
                    .processInstanceId(flowTask.getInstanceId())
                    .orderByHistoricTaskInstanceEndTime()
                    .desc()
                    .list();
            if (ObjectUtil.isNotEmpty(historicTaskInstance)) {
                String taskId = historicTaskInstance.get(0).getId();
                flowTask.setTaskId(taskId);
            }
        }

        return flowTask;
    }

    /**
     * 获取发起人名称
     *
     * @param processVariables 流程变量
     * @return 结果
     */
    private String getStartUserName(Map<String, Object> processVariables) {
        JSONObject startInfo = (JSONObject) processVariables.get("startInfo");
        return startInfo.getString("startUserName");
    }

    /**
     * 获取流程变量
     *
     * @param taskId 任务id
     * @return 任务变量
     */

    private Map<String, Object> getProcessVariables(String taskId) {
        HashMap<String, Object> map = new HashMap<>();
        // 流程变量
        HistoricTaskInstance historicTaskInstance = historyService
                .createHistoricTaskInstanceQuery()
                .includeProcessVariables()
                .finished()
                .taskId(taskId)
                .singleResult();
        if (Objects.nonNull(historicTaskInstance)) {
            map.putAll(historicTaskInstance.getProcessVariables());
        }
        try {
            Map<String, Object> taskVariables = taskService.getVariables(taskId);
            if (CollectionUtil.isNotEmpty(taskVariables)) {
                map.putAll(taskVariables);
            }
        } catch (Exception ignored) {
        }
        try {
            Map<String, Object> runVariables = runtimeService.getVariables(taskId);
            if (CollectionUtil.isNotEmpty(runVariables)) {
                map.putAll(runVariables);
            }
        } catch (Exception ignored) {
        }
        return map;
    }

    /**
     * 流程完成时间处理
     *
     * @param ms 毫秒值
     * @return 日期格式
     */
    private String getDate(long ms) {

        long day = ms / (24 * 60 * 60 * 1000);
        long hour = (ms / (60 * 60 * 1000) - day * 24);
        long minute = ((ms / (60 * 1000)) - day * 24 * 60 - hour * 60);
        long second = (ms / 1000 - day * 24 * 60 * 60 - hour * 60 * 60 - minute * 60);

        if (day > 0) {
            return day + "天" + hour + "小时" + minute + "分钟";
        }
        if (hour > 0) {
            return hour + "小时" + minute + "分钟";
        }
        if (minute > 0) {
            return minute + "分钟";
        }
        if (second > 0) {
            return second + "秒";
        } else {
            return 0 + "秒";
        }
    }
}